package summit.tests.tools
{
import flash.errors.IllegalOperationError;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.StatusEvent;

import summit.basecamp.helpers.ProjectHelper;
import summit.data.AccountToken;
import summit.events.BasecampAPIEvent;
import summit.net.BasecampLoader;
import org.tyemill.whitesands.TestContainer;

public class SummitTestContainer extends TestContainer
{
	private var _needProject:Boolean; 	// true means we need to retrieve an 
										// active project id.
	private static var s_projectId:Object;	// static object for storing a 
											// projectIds associated with
											// account urls
											
	private var _token:AccountToken;
	protected var projectId:String;
	private var _internalLoader:BasecampLoader; 
	protected var loader:BasecampLoader;
	protected var projectXML:XML;
	
	/** Gets the <code>AccountToken</code> used Basecamp Operations. **/
	protected function get token():AccountToken
	{
		return _token;
	}
	
	/** @inheritDoc 
	 * 
	 * @param
	 * needProject	<code>true</code> if the extending container needs the
	 * <code>projectId</code> property.
	 * **/
	public function SummitTestContainer(token:AccountToken, 
	needProject:Boolean = true)
	{
		super();
		_token = token;
		_needProject = needProject;
	
		// init must always be async - sometimes - we have to fake it.
		addEventListener(Event.INIT, self_CompleteInit);
		addEventListener(Event.SOUND_COMPLETE, self_Clear); // same with cleanup
	
		initializeLoader(null);
	}
	
	/** Initializes the Basecamp Loader **/
	protected function initializeLoader(OKHandler:Function = null):void
	{
		loader = new BasecampLoader();
		loader.accountToken = token;
		
		registerLoaderEvents(loader);	
		
		if(null != OKHandler) 
			loader.addEventListener(BasecampAPIEvent.OK, OKHandler);
	}
	
	/** Registers standard event handlers for a Basecamp Loader. **/
	protected function registerLoaderEvents(loader:BasecampLoader):void
	{
		loader.addEventListener(BasecampAPIEvent.ERROR, loader_Issue);
		loader.addEventListener(BasecampAPIEvent.FAIL, loader_Issue);
		loader.addEventListener(IOErrorEvent.IO_ERROR, loader_Issue);
		loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, 
		loader_Issue);
		loader.addEventListener(BasecampAPIEvent.OK, loader_OK);
	}
	
	/** Handles all Basecamp Loader problems - errors and failure. **/
	protected function loader_Issue(e:Event):void
	{
		var error:ErrorEvent
		
		if(e is BasecampAPIEvent) 
		{
			var apiEvent:BasecampAPIEvent = e as BasecampAPIEvent;
			error = new ErrorEvent(ErrorEvent.ERROR, false, false,
			apiEvent.resource + "::" + apiEvent.operation +
			" -> Type: " + apiEvent.type, -1);
		}
		else error = new ErrorEvent(ErrorEvent.ERROR, false, false,
		"Error", -2);
		
		// We throw - then can clean up by dismissing the dialog.
		throw new Error(error.text, error.errorID);
		
		dispatchErrorEvent(error);
	}
	
	/** Called to give harness a chance to clean-up **/
	protected function dispatchErrorEvent(e:ErrorEvent):void
	{
		dispatchEvent(e);
	}
	
	/** @inheritDoc **/
	override public function initialize():void
	{
		downloadProject();	
	}
	
	/** Override to get Init event - AFTER super has handled it **/
	protected function self_CompleteInit(e:Event):void
	{
		dispatchEvent(new StatusEvent(StatusEvent.STATUS, false, false, 
		TestContainer.STATUS_CODE_INIT, "complete"));	
	}
	
	/** @inheritDoc **/
	override public function cleanUp():void
	{
		dispatchEvent(new Event(Event.SOUND_COMPLETE));
	}
	
	
	private function loader_OK(e:BasecampAPIEvent):void
	{
		trace("** " + e.resource + "::" + e.operation + " complete.");
	}
	
	/** Standard handler for OK - automatically calls 'completeAsyncTest' **/
	protected function loader_OKComplete(e:BasecampAPIEvent):void
	{
		completeAsyncTest();
	}
	
	private function self_Clear(e:Event):void
	{
		dispatchEvent(new StatusEvent(StatusEvent.STATUS, false, false,
		TestContainer.STATUS_CODE_CLEAN, "complete"));	
	}
	
	/** @private Gets an active project for use by the test container. **/
	private function downloadProject():void
	{
		if(!_needProject) 
		{
			dispatchEvent(new Event(Event.INIT));	
			return;
		}
		
		if(s_projectId && true == s_projectId.hasOwnProperty(token.url))
		{
			projectXML = (s_projectId[token.url] as XML);
			projectId = projectXML.id;
			dispatchEvent(new Event(Event.INIT));
		}
		else
		{
			_internalLoader = new BasecampLoader();
			_internalLoader.accountToken = token;
			_internalLoader.addEventListener(BasecampAPIEvent.OK, 
			internalLoader_ProjectListOK);
			
			_internalLoader.addEventListener(BasecampAPIEvent.ERROR, 
			internalLoader_ProjectListIssue);
			_internalLoader.addEventListener(BasecampAPIEvent.FAIL,
			internalLoader_ProjectListIssue);
			_internalLoader.addEventListener(IOErrorEvent.IO_ERROR,
			internalLoader_ProjectListIssue);
			_internalLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
			internalLoader_ProjectListIssue);
						
			_internalLoader.load(ProjectHelper.list());
		}
	}
	
	
	/** @private Process the project list to get and record the first active 
	 * project. **/
	private function internalLoader_ProjectListOK(e:BasecampAPIEvent):void
	{
		for each(var project:XML in e.data.children())
		{
			if(project.status != "active") continue;
			
			if(!s_projectId) s_projectId = new Object();
			
			s_projectId[token.url] = project;
			
			projectId = project.id;
			projectXML = project;
			
			break;
		}
		
		if(!projectId) throw new IllegalOperationError(
		"Not active project found in account @: " + _token.url);
		
		self_CompleteInit(null); // we're already async - so party on
	}
	
	/** @private Probably means the account information is bad. **/
	private function internalLoader_ProjectListIssue(e:Event):void
	{
		throw new Error("Internal Loader was not able to get Project List" + 
				"check the account information and retry.");
	}
	
}
}